#ifndef LECTEURPHRASEAVECARBRE_H_
#define LECTEURPHRASEAVECARBRE_H_

#include "Symbole.h"
#include "LecteurSymbole.h"
#include "TableSymboles.h"
#include "Arbre.h"

#include <string>
using namespace std;

/*! \file LecteurPhraseAvecArbre.h
    \brief La spécification de la classe LecteurPhraseAvecArbre
    
    Décrit la liste des méthodes et attributs associés à la classe LecteurPhraseAvecArbre
    \author lazzamar
    \date 16/12/2012
 */
/*! \class LecteurPhraseAvecArbre
    \brief La classe représentant le lecteur de phrases du langage avec une
 * table et un arbre.
    
    Cette classe permet de lire les phrases du langage en les ajoutant dans une
 table des symboles et en les représentant sous forme d'arbre. Elle contient des
 méthodes pour analyser syntaxiquement étape par étape la grammaire du langage
 en créant les noeuds et feuilles au passage. Ces méthodes sont accompagnée de
 méthodes de test pour savoir quelle méthode d'analyse utiliser.
 Ces méthodes étant privées, elle ne sont pas documentées.
 Les méthodes suivantes sont utilisés pour déclencher l'analyse et obtenir la
 table et l'arbre.
    \li analyse
	\li getTs
    \li getArbre
*/

class LecteurPhraseAvecArbre
{
public:
	/*! \fn LecteurPhraseAvecArbre(string nomFich);
		\brief Constructeur de la classe LecteurPhraseAvecArbre

	 Ce constructeur construit le lecteur de symbole en ouvrant le fichier (en
	 appelant le constructeur de ls) pour vérifier la syntaxe du programme.
		\param string nomFich - le nom du fichier à ouvrir
	*/
	LecteurPhraseAvecArbre(string nomFich);	 // Construit un lecteur de phrase pour interpreter
	                                         //  le programme dans le fichier nomFich

	/*! \fn void analyse();
		\brief Analyse le programme.

	 Si le contenu du fichier est conforme à la grammaire, le programme se termine
	 normalement en affichant "Syntaxe Correcte". Sinon une exception est levée.
	 La table des symboles est construite ainsi que l'arbre abstrait.
	*/
	void analyse();  // Si le contenu du fichier est conforme à la grammaire,
	                 //   cette méthode se termine normalement et affiche un message "Syntaxe correcte".
                         //   la table des symboles (ts) et l'arbre abstrait (arbre) auront été construits
	                 // Sinon, le programme sera interrompu (exit).

	/*! \fn TableSymboles getTs ();
		\brief Accesseur à la table.

	 Permet de récupérer la table des symbole du programme analysé.
		\return La table des symbole.
	*/
	inline TableSymboles getTs ()    { return ts;    } // accesseur	
	
	/*! \fn TableSymboles getArbre ();
		\brief Accesseur de l'arbre.

	 Permet de récupérer l'arbre abstrait du programme analysé.
		\return un pointeur sur le noeud père de l'arbre abstrait.
	*/
	inline Noeud*        getArbre () { return arbre; } // accesseur
	

private:
	/*! \fn LecteurSymbole ls
		\brief Le lecteur de symbole utilisé pour l'analyse.
	*/	
    LecteurSymbole ls;    // le lecteur de symboles utilisé pour analyser le fichier
	
	/*! \fn TableSymbole ts
	 *  \brief La table des symboles valués.
	 */
    TableSymboles  ts;    // la table des symboles valués
	
	/*! \fn Noeud* arbre
	 *  \brief Le pointeur sur l'arbre abstrait.
	 */
    Noeud*         arbre; // l'arbre abstrait

    // implémentation de la grammaire
     // implémentation de la grammaire
    Noeud* programme();		//   <programme> ::= debut <seqInst> fin <EOF>
    Noeud* seqInst();	    //     <seq_ins> ::= <inst> ; { <inst> ; }
    Noeud* inst();			//        <inst> ::= <affectation> | <instSi> | <instSelon> | <instTq> | <instRepeter> | <instPour> | <instLire> | <instEcrire>
    Noeud* affectation();	// <affectation> ::= <variable> = <expression>
    Noeud* expression();	//  <expression> ::= <terme> { <opAdd> <terme> }
	Noeud* terme();			//       <terme> ::= <facteur> {<opMult> <facteur>}
    Noeud* facteur();		//     <facteur> ::= <entier>  |  <variable>  | <chaine> | <opUnaire> <expBool>  |  ( <expBool> )
	Noeud* expBool();		//	   <expBool> ::= <termBool> { <opOu> <termBool> }
	Noeud* termBool();		//	  <termBool> ::= <relation> { <opEt> <relation> }
	Noeud* relation();		//	  <relation> ::= <expression> { <opRel> <expression> }
	Symbole opEt();			//		  <opEt> ::= et
	Symbole opOu();			//		  <opOu> ::= ou
	Symbole opRel();		//		 <opRel> ::= == | != | < | <= | > | >=
    Symbole opAdd();		//       <opAdd> ::= + | -
	Symbole opMult();		//		<opMult> ::= * | /
	Symbole opUnaire();		//	  <opUnaire> ::= - | non
	
	Noeud* instSi();		//		<instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> }
							//					[ sinon <seqInst> ] finsi
	Noeud* instSelon();		//	 <instSelon> ::= selon ( <variable> )
							//					cas <expression> : <seqInst>
							//					{ cas <expression> : <seqInst> }
							//					[ defaut : <seqInst> ]
							//					finselon
	
	Noeud* instTq();		//		<instTq> ::= tantque ( <expBool> ) <seqInst> fintantque
	Noeud* instRepeter();	// <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
	Noeud* instPour();		//	  <instPour> ::= pour ( <affectation> ; <expBool> ; <inst> ) faire
							//					<seqInst> finfaire
	
	Noeud* instLire();		//	  <instLire> ::= lire ( <variable> )
	Noeud* instEcrire();	//	<instEcrire> ::= ecrire ( <expression> )

    // outils pour se simplifier l'analyse syntaxique
    void testerSymCour (string ch);  // si symbole courant != ch, erreur : on arrete le programme, sinon rien
    void sauterSymCour (string ch);  // si symbole courant == ch, on passe au symbole suivant, sinon erreur : on arrete
    void erreur (string mess);      // affiche les message d'erreur mess et arrete le programme

	// méthodes de test
	inline bool isVariable(){return (ls.getSymCour()=="<VARIABLE>");}
	inline bool isEntier(){return (ls.getSymCour()=="<ENTIER>");}
	inline bool isChaine(){return (ls.getSymCour()=="<CHAINE>");}
	inline bool isOpEt(){return (ls.getSymCour()=="et");}
	inline bool isOpOu(){return (ls.getSymCour()=="ou");}
	inline bool isOpRel(){return (ls.getSymCour()=="=="
			|| ls.getSymCour()=="!=" || ls.getSymCour()=="<="
			|| ls.getSymCour()==">=" || ls.getSymCour()==">"
			|| ls.getSymCour()=="<");}
	inline bool isOpAdd(){return (ls.getSymCour()=="+" || ls.getSymCour()=="-");}
	inline bool isOpMult(){return (ls.getSymCour()=="*" || ls.getSymCour()=="/");}
	inline bool isOpUnaire(){return (ls.getSymCour()=="-" || ls.getSymCour()=="non");}
	inline bool isInstSi(){return (ls.getSymCour()=="si");}
	inline bool isInstSelon(){return (ls.getSymCour()=="selon");}
	inline bool isInstTq(){return (ls.getSymCour()=="tantque");}
	inline bool isInstRepeter(){return (ls.getSymCour()=="repeter");}
	inline bool isInstPour(){return (ls.getSymCour()=="pour");}
	inline bool isInstLire(){return (ls.getSymCour()=="lire");}
	inline bool isInstEcrire(){return (ls.getSymCour()=="ecrire");}
};

#endif /* LECTEURPHRASEAVECARBRE_H_ */
